﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Forms;
using System.Collections.Generic;

using SBPweb.Modules.Modularity;
using SBPweb.Modules.Logging;
using SBPweb.Localization;
using SBPweb.Security.Authorization;

namespace SBPweb.MediaCenter.Presentation.WF
{
    public static class Program
    {

        #region Private fields

        private static ModuleLoader sModuleLoader;
        private static ResourceHandler sResourceHandler;
        private static MembershipUser sMembership;
        private static ILogManager sLogManager;

        private static string sModuleGroup = "Default";
        private static bool sIsInExplorerMode = false;

        #endregion

        #region Constructor logic

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Console.WriteLine("Environment.CurrentDirectory : " + Environment.CurrentDirectory);
            Console.WriteLine("AppDomain.CurrentDomain.BaseDirectory : " + AppDomain.CurrentDomain.BaseDirectory);
            Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            sMembership = new MembershipUser();

            try
            {
                sLogManager = new LogManager();
                sLogManager.Initialize();
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show(string.Format("Cannot initialize logger! Maybe you don't have rights writing to the log folder. Application exits.\n\n{0}", ex.ToString()), "Error", MessageBoxButtons.OK);
                Application.Exit();
                return;
            }

            LogManager.WriteVerbose(LogManager, string.Format("Process {0} starting.", System.Diagnostics.Process.GetCurrentProcess().ProcessName), "General");

            AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
            AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad);

            Program.sModuleLoader = new ModuleLoader(Properties.Settings.Default.PathOfModules, Properties.Settings.Default.PatternOfModules, Properties.Settings.Default.ApplicationTitle, Application.CompanyName, LogManager);
            Loader.ModuleLoading += new EventHandler<ModuleDescriptorEventArgs>(sModuleLoader_ModuleLoading);
            Loader.ModuleLoaded += new EventHandler<ModuleEventArgs>(sModuleLoader_ModuleLoaded);
            Loader.ModuleGroupLoaded += new EventHandler(sModuleLoader_ModuleGroupLoaded);
            Program.sResourceHandler = new ResourceHandler(typeof(MainForm), new List<CultureInfo>(SupportedCultures));

            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            LoadPersistency();

            LogManager.WriteVerbose(LogManager, string.Format("Process {0} persistency loaded.", System.Diagnostics.Process.GetCurrentProcess().ProcessName), "General");

            MainForm mainForm = new MainForm();
            mainForm.SecurityPrincipal = sMembership;

            Loader.Initialize(mainForm, sModuleGroup);

            LogManager.WriteVerbose(mainForm, string.Format("Process {0} modules loaded.", System.Diagnostics.Process.GetCurrentProcess().ProcessName), "General");

            Application.Run(mainForm);

            LogManager.WriteVerbose(mainForm, string.Format("Process {0} modules ending.", System.Diagnostics.Process.GetCurrentProcess().ProcessName), "General");

            SavePersistency();

            LogManager.WriteVerbose(mainForm, string.Format("Process {0} perisistency saved.", System.Diagnostics.Process.GetCurrentProcess().ProcessName), "General");

            Loader.Terminate();
        }

        #endregion

        #region Property accessors

        public static bool IsInExplorerMode
        {
            get
            {
                return sIsInExplorerMode;
            }
        }

        public static ModuleLoader Loader
        {
            get
            {
                return sModuleLoader;
            }
        }

        public static ResourceHandler Resources
        {
            get
            {
                return sResourceHandler;
            }
        }

        public static ILogManager LogManager
        {
            get
            {
                return sLogManager;
            }
        }

        internal static CultureInfo[] SupportedCultures
        {
            get
            {
                return sModuleLoader == null ? null : sModuleLoader.SupportedCultures.ToArray();
            }
        }

        #endregion

        #region Methods

        #region Event handlers

        #region ModuleLoader functions

        private static void sModuleLoader_ModuleGroupLoaded(object sender, EventArgs e)
        {
            Application.DoEvents();
        }

        private static void sModuleLoader_ModuleLoading(object sender, ModuleDescriptorEventArgs e)
        {
            string format = "Module {0} is loading.";
            try
            {
                format = LocalizationExtender.GetString("ModulLoading");
            }
            catch
            {
            }
            sModuleLoader.Host.LogManager.WriteInfo(sender, string.Format(format, e.Descriptor.ModuleTypeName), "ModuleLoader");
        }

        private static void sModuleLoader_ModuleLoaded(object sender, ModuleEventArgs e)
        {
            string format = "Module {0} has been loaded.";
            try
            {
                format = LocalizationExtender.GetString("ModulLoading");
            }
            catch
            {
            }
            sModuleLoader.Host.LogManager.WriteInfo(sender, string.Format(format, e.Module, e.Module.Version), "ModuleLoader");
        }

        private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args)
        {
            LogManager.WriteInfo(sender, string.Format("Assembly loaded: {0}", args.LoadedAssembly.FullName), "General");
        }

        private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            //This handler is called only when the common language runtime tries to bind to the assembly and fails.
            LogManager.WriteWarning(sender, string.Format("Assembly load failed: {0}", args.Name), "General");

            ////Retrieve the list of referenced assemblies in an array of AssemblyName.
            //Assembly MyAssembly, objExecutingAssemblies;
            //string strTempAssmbPath = "";

            //objExecutingAssemblies = Assembly.GetExecutingAssembly();
            //AssemblyName[] arrReferencedAssmbNames = objExecutingAssemblies.GetReferencedAssemblies();

            ////Loop through the array of referenced assembly names.
            //foreach (AssemblyName strAssmbName in arrReferencedAssmbNames)
            //{
            //    //Check for the assembly names that have raised the "AssemblyResolve" event.
            //    if (strAssmbName.FullName.Substring(0, strAssmbName.FullName.IndexOf(",")) == args.Name.Substring(0, args.Name.IndexOf(",")))
            //    {
            //        //Build the path of the assembly from where it has to be loaded.				
            //        strTempAssmbPath = "C:\\Myassemblies\\" + args.Name.Substring(0, args.Name.IndexOf(",")) + ".dll";
            //        break;
            //    }
            //}

            //if (!string.IsNullOrEmpty(strTempAssmbPath))
            //{
            //    //Load the assembly from the specified path. 					
            //    MyAssembly = Assembly.LoadFrom(strTempAssmbPath);

            //    LogManager.WriteInfo(sender, string.Format("Assembly explicitly loaded: {0}", args.Name), "General");
            //    //Return the loaded assembly.
            //    return MyAssembly;
            //}

            //LogManager.WriteError(sender, string.Format("Assembly cannot be loaded: {0}", args.Name), "General");
            return null;
        }

        #endregion

        #region Error handling functions

        private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            sModuleLoader.Host.LogManager.WriteCritical(sender, e.ExceptionObject as Exception, SeverityLevel.Critical.ToString());

            Exception exc = (e.ExceptionObject as Exception);
            while (exc is System.Reflection.TargetInvocationException && exc.InnerException != null)
            {
                exc = exc.InnerException;
            }

            throw exc;//MainForm.ShowErrorForm(exc);
        }

        private static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            sModuleLoader.Host.LogManager.WriteCritical(sender, e.Exception, SeverityLevel.Critical.ToString());

            Exception exc = e.Exception;

            while (exc is System.Reflection.TargetInvocationException && exc.InnerException != null)
            {
                exc = exc.InnerException;
            }

            throw exc; //MainForm.ShowErrorForm(exc);
        }

        #endregion

        #endregion

        #region Persistency

        private static void LoadPersistency()
        {
            //IStatePersistenceService persistenceService = sModuleLoader.Services.Get<IStatePersistenceService>();
            //if (persistenceService != null)
            //{
            //    PersistencyDictionary state = persistenceService.Load(sModuleLoader);
            //    sModuleGroup = state.GetString("ModuleGroup", string.Empty);
            //}
        }

        public static void SavePersistency()
        {
            //IStatePersistenceService persistenceService = sModuleLoader.Services.Get<IStatePersistenceService>();
            //if (persistenceService != null)
            //{
            //    PersistencyDictionary state = persistenceService.Load(sModuleLoader);
            //    state.SetString("ModuleGroup", sModuleLoader.CurrentModuleGroupName);
            //    persistenceService.Save(sModuleLoader, state);
            //}
        }

        #endregion

        #region Private helper functions

        private static void CheckIfRunningOnlyOnce()
        {
            string processName = Process.GetCurrentProcess().ProcessName;
            if (Process.GetProcessesByName(processName).Length > 1)
            {
                System.Windows.Forms.MessageBox.Show("You are not allowed to run two or more instances at same time!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
                Application.Exit();
                return;
            }
        }

        #endregion

        #endregion

    }

}